﻿using AiQiuQuan.Sport.Core;
using AiQiuQuan.Sport.Model.Enums;
using AiQiuQuan.Sport.Model.Models;
using AiQiuQuan.Sport.WebApi.Core;
using AiQiuQuan.Sport.WebApi.Entities;
using Microsoft.EntityFrameworkCore;
using System.Text.Json;

namespace AiQiuQuan.Sport.WebApi.Services.Impl
{
    /// <summary>
    /// 比赛服务私有方法
    /// </summary>
    public partial class GameService
    {
        #region private methods
        /// <summary>
        /// 获取队伍编号
        /// </summary>
        private List<string> GetTeamNoList(int teamCount)
        {
            var data = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
            var result = new List<string>();
            for (var i = 0; i < teamCount; i++)
            {
                result.Add(data[i].ToString());
            }

            return result;
        }

        /// <summary>
        /// 获取小组编号
        /// </summary>
        private List<int> GetGroupNoList(int teamCount)
        {
            var groupInfo = GetGroupCount(teamCount);
            var result = new List<int>();
            for (var i = 1; i <= groupInfo.Item1; i++)
            {
                result.Add(i);
            }

            return result;
        }

        /// <summary>
        /// 小组数，组成员数
        /// </summary>
        private Tuple<int, int> GetGroupCount(int teamCount)
        {
            switch (teamCount)
            {
                case 6:
                    return Tuple.Create(2, 3);
                case 8:
                    return Tuple.Create(2, 4);
                case 12:
                    return Tuple.Create(4, 3);
                case 16:
                    return Tuple.Create(4, 4);
                case 24:
                    return Tuple.Create(8, 3);
                case 32:
                    return Tuple.Create(8, 4);
            }

            return Tuple.Create(2, 3);
        }

        /// <summary>
        /// 是否单打
        /// </summary>
        private bool IsSingle(GameVersusEnum versusType)
        {
            return versusType == GameVersusEnum.Single || versusType == GameVersusEnum.MaleSingle || versusType == GameVersusEnum.FemaleSingle;
        }

        /// <summary>
        /// 生成比赛实体
        /// </summary>
        private Game CreateGame(GameAddDto model)
        {
            var game = _mapper.Map<Game>(model);
            game.State = GameStateEnum.Joining;
            game.ID = Guid.NewGuid();
            game.VersusType = JsonSerializer.Serialize(model.VersusTypeList);
            game.TeamCount = model.LimitCount;
            game.LimitCount = model.LimitCount;
            game.IsTogether = model.Type == GameTypeEnum.Team || model.VersusTypeList[0] == GameVersusEnum.Single || model.IsTogether;
            switch (model.Type)
            {
                case GameTypeEnum.Level:
                    game.TennisLevel = model.TennisLevel.GetValueOrDefault();
                    break;
                case GameTypeEnum.Age:
                    game.Age = model.Age.GetValueOrDefault();
                    game.GameSex = model.GameSex.GetValueOrDefault();
                    break;
            }

            return game;
        }

        /// <summary>
        /// 修改比赛实体
        /// </summary>
        private Game UpdateGame(GameUpdateDto model, Game game)
        {
            game.TeamCount = model.LimitCount;
            game.LimitCount = model.LimitCount;
            switch (model.Type)
            {
                case GameTypeEnum.Level:
                    game.TennisLevel = model.TennisLevel.GetValueOrDefault();
                    break;
                case GameTypeEnum.Age:
                    game.Age = model.Age.GetValueOrDefault();
                    game.GameSex = model.GameSex.GetValueOrDefault();
                    break;
            }

            return game;
        }

        /// <summary>
        /// 比赛报名验证
        /// </summary>
        private async Task<UnaryResult<GameJoinResultDto>> ValidJoinAsync(GameJoinRequestDto request)
        {
            var game = await _gameRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == request.GameId);
            if (game == null)
            {
                return UnaryResult.From<GameJoinResultDto>(10, null, "比赛不存在");
            }

            if (game.Type == GameTypeEnum.Team)
            {
                if (string.IsNullOrWhiteSpace(request.Name) || string.IsNullOrWhiteSpace(request.HeadUrl))
                {
                    return UnaryResult.From<GameJoinResultDto>(10, null, "团体赛时，队伍名称、头像为空");
                }
            }

            if (game.Price != request.Amount)
            {
                return UnaryResult.From<GameJoinResultDto>(10, null, "比赛金额不正确");
            }

            var gameTeamList = await _gameTeamRepository.AsNoTracking().Where(m => m.GameId == request.GameId).ToListAsync();
            var limitCount = gameTeamList.Where(m => m.JoinState == GameJoinStateEnum.JoinCompleted || m.JoinState == GameJoinStateEnum.Joining).GroupBy(m => m.BusinessId).Count();
            if (limitCount + request.TeamDetailList.Count > (game.IsTogether ? game.LimitCount : game.LimitCount * 2))
            {
                return UnaryResult.From<GameJoinResultDto>(10, null, "比赛队伍数量超限");
            }

            foreach (var item in request.TeamDetailList)
            {
                if (!game.IsTogether && !IsSingle(item.VersusType) && item.User2Id.HasValue)
                {
                    return UnaryResult.From<GameJoinResultDto>(10, null, "双打不一起报名");
                }

                if (request.TeamDetailList.Count(m => item.User1Id == m.User1Id || item.User1Id == m.User2Id) >= 2)
                {
                    return UnaryResult.From<GameJoinResultDto>(10, null, "用户1重复");
                }

                if (item.User2Id.HasValue && request.TeamDetailList.Count(m => item.User2Id == m.User1Id || item.User2Id == m.User2Id) >= 2)
                {
                    return UnaryResult.From<GameJoinResultDto>(10, null, "用户2重复");
                }

                if (!IsSingle(item.VersusType) && !item.User2Id.HasValue)
                {
                    return UnaryResult.From<GameJoinResultDto>(10, null, "双打时，用户2为空");
                }

                if (gameTeamList.Any(m => m.User1Id == item.User1Id || m.User2Id == item.User1Id))
                {
                    return UnaryResult.From<GameJoinResultDto>(10, null, "报名用户1重复");
                }

                if (item.User2Id.HasValue && gameTeamList.Any(m => m.User1Id == item.User2Id || m.User2Id == item.User2Id))
                {
                    return UnaryResult.From<GameJoinResultDto>(10, null, "报名用户2重复");
                }
            }

            return UnaryResult.Succeed<GameJoinResultDto>(null);
        }

        /// <summary>
        /// 生成比赛队伍
        /// </summary>
        private async Task<List<GameTeam>> CreateGameTeamAsync(GameJoinRequestDto request, Game game, GameOrder gameOrder)
        {
            var teamList = new List<GameTeam>();
            var businessId = Guid.NewGuid();
            foreach (var item in request.TeamDetailList)
            {
                var team = new GameTeam
                {
                    GameId = request.GameId,
                    VersusType = item.VersusType,
                    GameOrderId = gameOrder.ID,
                    BusinessId = businessId,
                    User1Id = item.User1Id,
                    User2Id = item.User2Id,
                    JoinState = GameJoinStateEnum.Joining,
                    PayState = PayOrderStateEnum.NotPay,
                    JoinUserId = _currentInfo.UserId,
                    IsTogether = game.IsTogether,
                    Name = request.Name ?? string.Empty,
                    HeadUrl = request.HeadUrl,
                    TeamNo = ""
                };
                if (game.Type != GameTypeEnum.Team)
                {
                    var user = await _baseUserRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == item.User1Id);
                    team.Name = user.U_RealName ?? user.U_NickName;
                    if (!IsSingle(item.VersusType))
                    {
                        user = await _baseUserRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == item.User2Id);
                        team.Name = $"{team.Name} {user.U_RealName ?? user.U_NickName}";
                    }
                }

                teamList.Add(team);
            }

            return teamList;
        }

        /// <summary>
        /// 生成比赛业务订单
        /// </summary>
        private async Task<GameOrder> CreateGameOrderAsync(GameJoinRequestDto request, Game game)
        {
            var user = await _baseUserRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == _currentInfo.UserId);
            return new GameOrder
            {
                ID = Guid.NewGuid(),
                Name = game.Name,
                BusinessId = game.ID,
                BusinessType = BusinessTypeEnum.Game,
                OrderNo = Tool.BuildPayOrderNo(BusinessTypeEnum.Game),
                GameDate = game.StartDate,
                StartTime = game.StartTime,
                EndTime = game.EndTime,
                Address = game.VenueName,
                PayType = PayTypeEnum.None,
                State = GameOrderStateEnum.NotPay,
                JoinCount = request.TeamDetailList.Sum(m => IsSingle(m.VersusType) ? 1 : 2),
                Price = game.Price,
                OrderAmount = game.Price,
                PayAmount = game.Price,
                Bonus = 0,
                BonusAmount = 0,
                CouponId = null,
                CouponAmount = 0,
                Remark = $"{game.Name}报名:{user.U_RealName ?? user.U_NickName}",
                RefundAmount = 0,
                RefundRemark = null,
                UserId = user.ID,
                Mobile = user.U_PhoneNum,
                UserName = user.U_RealName ?? user.U_NickName
            };
        }

        /// <summary>
        /// 生成小组实体
        /// </summary>
        private List<GameGroup> CreateGameGroup(GameInnerDto inner)
        {
            var groupInfo = GetGroupCount(inner.TeamCount);
            var groupList = new List<GameGroup>();
            foreach (var item in inner.VersusTypeList)
            {
                for (var i = 1; i <= groupInfo.Item1; i++)
                {
                    var group = new GameGroup
                    {
                        ID = Guid.NewGuid(),
                        GameId = inner.GameId,
                        VersusType = item,
                        GroupName = $"小组{Tool.SingleNumberToChineseNumber(i)}",
                        GroupNo = i,
                    };
                    groupList.Add(group);
                }
            }

            return groupList;
        }

        /// <summary>
        /// 获取小组抽签队伍列表
        /// </summary>
        private async Task<List<GameGroupDrawTeamDto>> GetGroupDrawTeamListAsync(GameRequestDto request)
        {
            var quaryable = from team in _gameTeamRepository.AsNoTracking()
                            join user1 in _baseUserRepository.AsNoTracking()
                            on team.User1Id equals user1.ID into user1d
                            from user1 in user1d.DefaultIfEmpty()
                            join user2 in _baseUserRepository.AsNoTracking()
                            on team.User2Id equals user2.ID into user2d
                            from user2 in user2d.DefaultIfEmpty()
                            where team.GameId == request.GameId && team.VersusType == request.VersusType
                            select new GameGroupDrawTeamDto
                            {
                                ID = team.ID,
                                GameId = team.GameId,
                                VersusType = team.VersusType,
                                Name = team.Name,
                                HeadUrl = team.HeadUrl,
                                GroupNo = team.GroupNo,
                                TeamNo = team.TeamNo,
                                User1Id = team.User1Id,
                                User1Name = user1.U_RealName ?? user1.U_NickName,
                                User1HeadUrl = user1.U_Headportrait,
                                User2Id = team.User2Id,
                                User2Name = user2.U_RealName ?? user2.U_NickName,
                                User2HeadUrl = user2.U_Headportrait,
                                CreateTime = user2.CreateTime
                            };
            var teamlist = await quaryable.ToListAsync();
            foreach (var item in teamlist)
            {
                item.User1TennisLevel = (await _baseUserService.GetTennisLevelAsync(item.User1Id)).LevelName;
                if (item.User2Id != null)
                {
                    item.User2TennisLevel = (await _baseUserService.GetTennisLevelAsync(item.User2Id.Value)).LevelName;
                }
            }

            return teamlist;
        }

        /// <summary>
        /// 小组抽签验证
        /// </summary>
        private async Task<UnaryResult> ValidGroupDrawAsync(GameGroupDrawLotsRequestDto request, Game game, GameVersusEnum versusType)
        {
            if (!await _gameGroupRepository.AsNoTracking().AnyAsync(m => m.GameId == game.ID && m.VersusType == versusType))
            {
                return UnaryResult.Faild(10, "小组不存在");
            }

            if (await _gameGroupRepository.AsNoTracking().AnyAsync(m => m.GameId == game.ID && m.VersusType == versusType && m.IsFinished))
            {
                return UnaryResult.Faild(10, "小组赛已开始");
            }

            if (await _gameGroupVersusRepository.AsNoTracking().AnyAsync(m => m.GameId == game.ID && m.VersusType == versusType && m.Team1Score + m.Team2Score > 0))
            {
                return UnaryResult.Faild(10, "小组赛已开始");
            }

            foreach (var item in request.TeamList)
            {
                if (string.IsNullOrWhiteSpace(item.TeamNo) || item.GroupNo <= 0)
                {
                    return UnaryResult.Faild(10, "小组抽签组号队伍号必须同时存在");
                }
            }

            var group = request.TeamList.GroupBy(m => m.GroupNo);
            var groupCount = GetGroupCount(game.TeamCount);
            var teamCount = game.IsTogether ? groupCount.Item2 : groupCount.Item2 * 2;
            foreach (var item in group)
            {
                if (item.Key >= 1 && item.Count() > teamCount)
                {
                    return UnaryResult.Faild(10, $"小组{item.Key}成员超出{teamCount}");
                }

                var teamGroup = item.GroupBy(m => m.TeamNo);
                foreach (var item2 in teamGroup)
                {
                    if (game.IsTogether && item2.Count() != 1)
                    {
                        return UnaryResult.Faild(10, $"小组【{item.Key}】抽签,队伍号不正确");
                    }

                    if (!game.IsTogether && item.Count() != 2)
                    {
                        return UnaryResult.Faild(10, $"小组【{item.Key}】抽签,队伍号不正确");
                    }
                }
            }

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 小组自动抽签队伍相关数据设置
        /// </summary>
        /// <param name="teamList">待抽签队伍</param>
        /// <param name="game">比赛</param>
        private void SetGroupAutoDrawData(List<GameGroupDrawTeamDto> teamList, Game game)
        {
            if (teamList.Any())
            {
                var groupNoList = GetGroupNoList(game.TeamCount);
                var groupCountInfo = GetGroupCount(game.TeamCount);
                var teamNoList = GetTeamNoList(groupCountInfo.Item2);
                //设置小组号
                var groupStep = game.IsTogether ? groupCountInfo.Item2 : groupCountInfo.Item2 * 2;
                foreach (var item in teamList)
                {
                    var index = teamList.IndexOf(item);
                    var groupNoIndex = index / groupStep;

                    if (groupNoIndex < groupNoList.Count)
                    {
                        item.GroupNo = groupNoList[groupNoIndex];
                    }
                }

                //设置队伍号
                var teamStep = game.IsTogether ? 1 : 2;
                foreach (var item in teamList.GroupBy(m => m.GroupNo))
                {
                    if (item.Key > 0)
                    {
                        var templist = item.ToList();
                        foreach (var item2 in templist)
                        {
                            var index = templist.IndexOf(item2);
                            var teamIndex = index / teamStep;
                            if (teamIndex < teamNoList.Count)
                            {
                                item2.TeamNo = teamNoList[teamIndex];
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 单项目生成小组成员及小组对阵,有用户成员
        /// </summary>
        private async Task CreateGameGroupUserAndVersusAsync(GameInnerDto inner, GameGroupDrawLotsRequestDto request, List<GameGroupUser> groupUserList, List<GameGroupVersus> groupVersusList)
        {
            request.TeamList ??= new List<GameGroupDrawLotsDetalDto>();
            List<GameGroupDrawLotsDetalDto> teamList = null;
            var tempGroupUserList = await _gameGroupUserRepository.Where(m => m.GameId == inner.GameId && m.VersusType == inner.VersusTypeList[0]).OrderBy(m => m.GroupNo).ToListAsync();
            var tempGroupVersusList = await _gameGroupVersusRepository.Where(m => m.GameId == inner.GameId && m.VersusType == inner.VersusTypeList[0]).OrderBy(m => m.GroupNo).ToListAsync();
            //将抽签队伍按对应编号入位小组成员
            foreach (var item in tempGroupUserList)
            {
                teamList = request.TeamList.Where(m => item.GroupNo == m.GroupNo && item.TeamNo == $"{m.GroupNo}{m.TeamNo}").ToList();
                if (teamList.Any())
                {
                    item.User1Id = teamList.First().User1Id;
                    item.User2Id = teamList.Count == 2 ? teamList.Last().User1Id : teamList.First().User2Id;
                    groupUserList.Add(item);
                }
            }

            //将对应的小组成员入位小组对阵
            GameGroupUser tempGroupUser = null;
            foreach (var item in tempGroupVersusList)
            {
                var isUpdate = false;
                tempGroupUser = groupUserList.FirstOrDefault(m => item.GroupNo == m.GroupNo && item.Team1No == m.TeamNo);
                if (tempGroupUser != null)
                {
                    item.Team1User1Id = tempGroupUser.User1Id;
                    item.Team1User2Id = tempGroupUser.User2Id;
                    isUpdate = true;
                }

                tempGroupUser = groupUserList.FirstOrDefault(m => item.GroupNo == m.GroupNo && item.Team2No == m.TeamNo);
                if (tempGroupUser != null)
                {
                    item.Team2User1Id = tempGroupUser.User1Id;
                    item.Team2User2Id = tempGroupUser.User2Id;
                    isUpdate = true;
                }

                if (isUpdate)
                {
                    groupVersusList.Add(item);
                }
            }
        }

        /// <summary>
        /// 单项目生成小组成员及小组对阵
        /// </summary>
        private void CreateGameGroupUserAndVersus(GameInnerDto inner, List<GameGroup> groupList, List<GameGroupUser> groupUserList, List<GameGroupVersus> groupVersusList)
        {
            var groupInfo = GetGroupCount(inner.TeamCount);
            var teamNoList = GetTeamNoList(groupInfo.Item2);
            var tempGroupList = CreateGameGroup(inner);
            groupList.AddRange(tempGroupList);
            foreach (var item in tempGroupList)
            {
                //生成组成员
                var groupUsers = new List<GameGroupUser>();
                foreach (var item2 in teamNoList)
                {
                    var groupUser = new GameGroupUser
                    {
                        GameId = item.GameId,
                        VersusType = item.VersusType,
                        GroupId = item.ID,
                        GroupNo = item.GroupNo,
                        TeamNo = $"{item.GroupNo}{item2}",
                        User1Id = null,
                        User2Id = null,
                    };
                    groupUsers.Add(groupUser);
                    groupUserList.Add(groupUser);
                }

                //生成组对阵
                if (groupUsers.Count % 2 == 1)
                {
                    groupUsers.Add(new GameGroupUser());
                }

                for (var i = 1; i <= groupUsers.Count - 1; i++)
                {
                    var loopIndex = 0;
                    var loopNo = 1;
                    while (loopIndex < groupUsers.Count)
                    {
                        var groupUser1 = groupUsers[loopIndex];
                        var groupUser2 = groupUsers[loopIndex + 1];
                        if (groupUser1.GroupNo != 0 && groupUser2.GroupNo != 0)
                        {
                            groupVersusList.Add(new GameGroupVersus
                            {
                                GameId = item.GameId,
                                GroupId = item.ID,
                                GroupNo = item.GroupNo,
                                VersusType = item.VersusType,
                                IsDouble = !IsSingle(item.VersusType),
                                RoundsNo = i,
                                LoopNo = loopNo,
                                Team1No = groupUser1.TeamNo,
                                Team1User1Id = groupUser1.User1Id,
                                Team1User2Id = groupUser1.User2Id,
                                Team2No = groupUser2.TeamNo,
                                Team2User1Id = groupUser2.User1Id,
                                Team2User2Id = groupUser2.User2Id,
                            });
                            loopNo++;
                        }

                        loopIndex += 2;
                    }

                    //交换成员
                    var old = groupUsers[1];
                    groupUsers.RemoveAt(1);
                    groupUsers.Add(old);
                }

                groupUsers.Clear();
                groupUsers = null;
            }

            tempGroupList.Clear();
        }

        /// <summary>
        /// 单项目生成淘汰赛轮次及对阵
        /// </summary>
        private void CreateGameKnockoutVersus(Game game, GameVersusEnum versusType, List<GameKnockoutRounds> knockoutRoundsList, List<GameKnockoutVersus> knockoutVersusList)
        {
            var groupInfo = GetGroupCount(game.TeamCount);
            var knockoutCount = groupInfo.Item1 * game.GroupRank;
            var tempKnockoutRoundsList = new List<GameKnockoutRounds>();
            var tempKnockoutVersusList = new List<GameKnockoutVersus>();
            //生成淘汰赛轮次
            while (knockoutCount >= 2)
            {
                var rounds = new GameKnockoutRounds
                {
                    ID = Guid.NewGuid(),
                    GameId = game.ID,
                    VersusType = versusType,
                    KnockoutCount = knockoutCount,
                    Name = knockoutCount == 4 ? $"半决赛" : (knockoutCount == 2 ? "决赛" : $"1/{knockoutCount / 2}决赛"),
                    IsHaveExtra = knockoutCount <= game.KnockoutRank && knockoutCount > 2
                };
                knockoutRoundsList.Add(rounds);
                tempKnockoutRoundsList.Add(rounds);
                knockoutCount /= 2;
            }

            //生成淘汰赛对阵
            foreach (var item in tempKnockoutRoundsList)
            {
                //正赛
                for (var i = 1; i <= item.KnockoutCount / 2; i++)
                {
                    var konckoutVresus = new GameKnockoutVersus
                    {
                        GameId = item.GameId,
                        VersusType = item.VersusType,
                        KnockoutRoundsId = item.ID,
                        KnockoutName = item.Name,
                        KnockoutCount = item.KnockoutCount,
                        LoopNo = i,
                        Team1No = "",
                        Team2No = "",
                        IsDouble = !IsSingle(item.VersusType),
                        StartRank = 1,
                        EndRank = item.KnockoutCount
                    };
                    knockoutVersusList.Add(konckoutVresus);
                    tempKnockoutVersusList.Add(konckoutVresus);
                }

                //附加赛
                if (item.IsHaveExtra)
                {
                    AddKnockoutExtraVersus((item.KnockoutCount / 2) + 1, item.KnockoutCount, tempKnockoutRoundsList, tempKnockoutVersusList);
                }
            }

            tempKnockoutRoundsList.Clear();
            tempKnockoutVersusList.Clear();
        }

        /// <summary>
        /// 增加淘汰赛附加赛
        /// </summary>
        private void AddKnockoutExtraVersus(int startRank, int endRank, List<GameKnockoutRounds> knockoutRoundsList, List<GameKnockoutVersus> knockoutVersusList)
        {
            var knockoutCount = endRank - startRank + 1;
            var knockoutRounds = knockoutRoundsList.FirstOrDefault(m => m.KnockoutCount == knockoutCount);
            if (knockoutRounds == null)
            {
                return;
            }

            for (var i = 1; i <= knockoutCount / 2; i++)
            {
                var konckoutVresus = new GameKnockoutVersus
                {
                    GameId = knockoutRounds.GameId,
                    VersusType = knockoutRounds.VersusType,
                    KnockoutRoundsId = knockoutRounds.ID,
                    KnockoutName = knockoutRounds.Name,
                    KnockoutCount = knockoutCount,
                    LoopNo = i,
                    Team1No = "",
                    Team2No = "",
                    IsDouble = !IsSingle(knockoutRounds.VersusType),
                    StartRank = startRank,
                    EndRank = endRank,
                    IsExtra = true
                };
                knockoutVersusList.Add(konckoutVresus);
            }

            if (knockoutCount > 2)
            {
                var upStart = startRank;
                var upEnd = startRank + (knockoutCount / 2) - 1;
                var downStart = startRank + (knockoutCount / 2);
                var downEnd = endRank;
                AddKnockoutExtraVersus(upStart, upEnd, knockoutRoundsList, knockoutVersusList);
                AddKnockoutExtraVersus(downStart, downEnd, knockoutRoundsList, knockoutVersusList);
            }
        }

        /// <summary>
        /// 设置首轮淘汰赛成员数据
        /// </summary>
        private async Task<List<GameKnockoutVersus>> SetFirstKnockoutVersusMember(GameKnockoutVersusInitDto request, List<GameGroupUser> groupUserList)
        {
            var firstKnockoutRounds = await _gameKnockoutRoundsRepository.AsNoTracking()
               .Where(m => m.GameId == request.GameId && m.VersusType == request.VersusType).OrderByDescending(m => m.KnockoutCount)
               .FirstOrDefaultAsync();
            var firstKonockoutVersusList = await _gameKnockoutVersusRepository
                .Where(m => m.GameId == request.GameId && m.VersusType == request.VersusType && m.KnockoutRoundsId == firstKnockoutRounds.ID)
                .ToListAsync();
            firstKonockoutVersusList = firstKonockoutVersusList.OrderBy(m => m.LoopNo).ToList();
            var game = await _gameRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == request.GameId);
            groupUserList = groupUserList.OrderBy(m => m.GroupNo).ThenBy(m => m.Rank).Where(m => m.Rank <= game.GroupRank).ToList();

            for (var i = 0; i < groupUserList.Count; i += 2 * game.GroupRank)
            {
                var loopNo = i / 2;
                if (game.GroupRank == 1)
                {
                    firstKonockoutVersusList[loopNo].Team1No = groupUserList[i].TeamNo;
                    firstKonockoutVersusList[loopNo].Team1User1Id = groupUserList[i].User1Id;
                    firstKonockoutVersusList[loopNo].Team1User2Id = groupUserList[i].User2Id;
                    firstKonockoutVersusList[loopNo].Team2No = groupUserList[i + 1].TeamNo;
                    firstKonockoutVersusList[loopNo].Team2User1Id = groupUserList[i + 1].User1Id;
                    firstKonockoutVersusList[loopNo].Team2User2Id = groupUserList[i + 1].User2Id;
                }
                else if (game.GroupRank == 2)
                {
                    firstKonockoutVersusList[loopNo].Team1No = groupUserList[i].TeamNo;
                    firstKonockoutVersusList[loopNo].Team1User1Id = groupUserList[i].User1Id;
                    firstKonockoutVersusList[loopNo].Team1User2Id = groupUserList[i].User2Id;
                    firstKonockoutVersusList[loopNo].Team2No = groupUserList[i + 3].TeamNo;
                    firstKonockoutVersusList[loopNo].Team2User1Id = groupUserList[i + 3].User1Id;
                    firstKonockoutVersusList[loopNo].Team2User2Id = groupUserList[i + 3].User2Id;

                    firstKonockoutVersusList[loopNo + 1].Team1No = groupUserList[i + 2].TeamNo;
                    firstKonockoutVersusList[loopNo + 1].Team1User1Id = groupUserList[i + 2].User1Id;
                    firstKonockoutVersusList[loopNo + 1].Team1User2Id = groupUserList[i + 2].User2Id;
                    firstKonockoutVersusList[loopNo + 1].Team2No = groupUserList[i + 1].TeamNo;
                    firstKonockoutVersusList[loopNo + 1].Team2User1Id = groupUserList[i + 1].User1Id;
                    firstKonockoutVersusList[loopNo + 1].Team2User2Id = groupUserList[i + 1].User2Id;
                }
            }

            return firstKonockoutVersusList;
        }

        /// <summary>
        /// 进入下一轮对阵
        /// </summary>
        private async Task EnterKnockouVersusNexLoopAsync(GameKnockoutVersus versus)
        {
            if (versus == null || versus.EndRank == versus.StartRank + 1)
            {
                return;
            }

            var loopNo = versus.LoopNo % 2 == 0 ? versus.LoopNo / 2 : (versus.LoopNo / 2) + 1;
            var winStartRank = versus.StartRank;
            var winEndRank = versus.EndRank / 2;
            var failStartRank = (versus.EndRank / 2) + 1;
            var failEndRank = versus.EndRank;
            var nextVersusList = new List<GameKnockoutVersus>();

            //正赛
            if (!versus.IsExtra)
            {
                //赢的一方正向晋级
                var nextWinVersus = await _gameKnockoutVersusRepository
                     .FirstOrDefaultAsync(m => m.GameId == versus.GameId && m.VersusType == versus.VersusType
                     && m.StartRank == winStartRank && m.EndRank == winEndRank && m.LoopNo == loopNo);
                //赋值
                SetNextKnockoutVersusTeam(nextWinVersus, versus, true, nextVersusList);

                //假如本轮有附加赛，输的一队进行附加赛对阵
                var currentKnockoutRounds = await _gameKnockoutRoundsRepository.FirstOrDefaultAsync(m => m.ID == versus.KnockoutRoundsId);
                if (currentKnockoutRounds.IsHaveExtra)
                {
                    var nextFailVersus = await _gameKnockoutVersusRepository
                        .FirstOrDefaultAsync(m => m.GameId == versus.GameId && m.VersusType == versus.VersusType && m.IsExtra
                        && m.StartRank == failStartRank && m.EndRank == failEndRank && m.LoopNo == loopNo);
                    //赋值
                    SetNextKnockoutVersusTeam(nextFailVersus, versus, false, nextVersusList);
                }
            }
            //附加赛
            else
            {
                //赢的一方正向晋级
                var nextWinVersus = await _gameKnockoutVersusRepository
                     .FirstOrDefaultAsync(m => m.GameId == versus.GameId && m.VersusType == versus.VersusType && m.IsExtra
                     && m.StartRank == winStartRank && m.EndRank == winEndRank && m.LoopNo == loopNo);
                //赋值
                SetNextKnockoutVersusTeam(nextWinVersus, versus, true, nextVersusList);

                //输的一队反向晋级
                var nextFailVersus = await _gameKnockoutVersusRepository
                        .FirstOrDefaultAsync(m => m.GameId == versus.GameId && m.VersusType == versus.VersusType && m.IsExtra
                        && m.StartRank == failStartRank && m.EndRank == failEndRank && m.LoopNo == loopNo);
                //赋值
                SetNextKnockoutVersusTeam(nextFailVersus, versus, false, nextVersusList);
            }

            using (var uow = _unitOfWorkManager.Begin())
            {
                foreach (var item in nextVersusList)
                {
                    await _gameKnockoutVersusRepository.UpdateAsync(item);
                }

                await uow.CompleteAsync();
            }
        }

        /// <summary>
        /// 设置淘汰赛下一轮数据;
        /// </summary>
        /// <param name="next">GameKnockoutVersus</param>
        /// <param name="current">GameKnockoutVersus</param>
        /// <param name="isWin">是否赢方晋级</param>
        /// <param name="result">GameKnockoutVersus列表</param>
        private void SetNextKnockoutVersusTeam(GameKnockoutVersus next, GameKnockoutVersus current, bool isWin, List<GameKnockoutVersus> result)
        {
            if (next != null)
            {
                var team1Toal = current.Team1Score + current.Team1ExtraScore;
                var team2Toal = current.Team2Score + current.Team2ExtraScore;

                var teamNo = team1Toal > team2Toal ? current.Team1No : current.Team2No;
                var userId1 = team1Toal > team2Toal ? current.Team1User1Id : current.Team2User1Id;
                var userId2 = team1Toal > team2Toal ? current.Team1User2Id : current.Team2User2Id;
                if (!isWin)
                {
                    teamNo = team1Toal < team2Toal ? current.Team1No : current.Team2No;
                    userId1 = team1Toal < team2Toal ? current.Team1User1Id : current.Team2User1Id;
                    userId2 = team1Toal < team2Toal ? current.Team1User2Id : current.Team2User2Id;
                }

                if (current.LoopNo % 2 == 1)
                {
                    next.Team1No = teamNo;
                    next.Team1User1Id = userId1;
                    next.Team1User2Id = userId2;
                }
                else
                {
                    next.Team2No = teamNo;
                    next.Team2User1Id = userId1;
                    next.Team2User2Id = userId2;
                }

                result.Add(next);
            }
        }

        /// <summary>
        /// 计算比赛积分和淘汰赛排名
        /// </summary>
        private async Task CalculatePointAsync(GameKnockoutVersus current, List<GameTeamPointAddDto> gamePointList)
        {
            var game = await _gameRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == current.GameId);
            var pointRule = await _gamePointRuleRepository.AsNoTracking().FirstOrDefaultAsync(m => m.GameType == game.Type && m.TeamCount == game.TeamCount);
            if (pointRule != null)
            {
                var times = 1;
                try
                {
                    switch (pointRule.GameType)
                    {
                        case GameTypeEnum.Level:
                            var leveRuleDetailList = JsonSerializer.Deserialize<List<GameTennisLevelPointRuleDetail>>(pointRule.TimesRule);
                            times = leveRuleDetailList.FirstOrDefault(m => m.VersusType == current.VersusType && m.Level == game.TennisLevel).Times;
                            break;
                        case GameTypeEnum.Age:
                            var ageRuleDetailList = JsonSerializer.Deserialize<List<GameAgePointRuleDetail>>(pointRule.TimesRule);
                            times = ageRuleDetailList.FirstOrDefault(m => m.Age == game.Age).Times;
                            break;
                        case GameTypeEnum.Team:
                            var teamRuleDetailList = JsonSerializer.Deserialize<List<GameTeamPointRuleDetail>>(pointRule.TimesRule);
                            times = teamRuleDetailList.FirstOrDefault(m => m.VersusType == current.VersusType).Times;
                            break;
                    }
                }
                catch { }

                var team1Toal = current.Team1Score + current.Team1ExtraScore;
                var team2Toal = current.Team2Score + current.Team2ExtraScore;
                if (current.EndRank == 16 || current.EndRank == 8 || (current.EndRank == 4 && current.StartRank == 1 && game.KnockoutRank == 2))
                {
                    gamePointList.Add(new GameTeamPointAddDto
                    {
                        GameId = current.GameId,
                        VersusType = current.VersusType,
                        TeamNo = team1Toal < team2Toal ? current.Team1No : current.Team2No,
                        User1Id = team1Toal < team2Toal ? current.Team1User1Id : current.Team2User1Id,
                        User2Id = team1Toal < team2Toal ? current.Team1User2Id : current.Team2User2Id,
                        Point = current.EndRank == 16 ? pointRule.Rank16Point * times :
                                    current.EndRank == 8 ? pointRule.Rank8Point * times : pointRule.Rank4Point * times
                    });
                }
                else
                {
                    if (current.EndRank == 4 && current.StartRank == 3)
                    {
                        gamePointList.Add(new GameTeamPointAddDto
                        {
                            GameId = current.GameId,
                            VersusType = current.VersusType,
                            TeamNo = team1Toal < team2Toal ? current.Team1No : current.Team2No,
                            User1Id = team1Toal < team2Toal ? current.Team1User1Id : current.Team2User1Id,
                            User2Id = team1Toal < team2Toal ? current.Team1User2Id : current.Team2User2Id,
                            Point = pointRule.Rank4Point * times
                        });
                        gamePointList.Add(new GameTeamPointAddDto
                        {
                            GameId = current.GameId,
                            VersusType = current.VersusType,
                            TeamNo = team1Toal > team2Toal ? current.Team1No : current.Team2No,
                            User1Id = team1Toal > team2Toal ? current.Team1User1Id : current.Team2User1Id,
                            User2Id = team1Toal > team2Toal ? current.Team1User2Id : current.Team2User2Id,
                            Point = pointRule.Rank3Point * times
                        });
                    }
                    else if (current.EndRank == 2)
                    {
                        gamePointList.Add(new GameTeamPointAddDto
                        {
                            GameId = current.GameId,
                            VersusType = current.VersusType,
                            TeamNo = team1Toal < team2Toal ? current.Team1No : current.Team2No,
                            User1Id = team1Toal < team2Toal ? current.Team1User1Id : current.Team2User1Id,
                            User2Id = team1Toal < team2Toal ? current.Team1User2Id : current.Team2User2Id,
                            Point = pointRule.Rank2Point * times
                        });
                        gamePointList.Add(new GameTeamPointAddDto
                        {
                            GameId = current.GameId,
                            VersusType = current.VersusType,
                            TeamNo = team1Toal > team2Toal ? current.Team1No : current.Team2No,
                            User1Id = team1Toal > team2Toal ? current.Team1User1Id : current.Team2User1Id,
                            User2Id = team1Toal > team2Toal ? current.Team1User2Id : current.Team2User2Id,
                            Point = pointRule.Rank1Point * times
                        });
                    }
                }
            }
        }

        /// <summary>
        /// 结束比赛积分计算
        /// </summary>
        private async Task FinishGameCalculatePointAsync(Game game)
        {
            var versusTypeList = JsonSerializer.Deserialize<List<GameVersusEnum>>(game.VersusType);
            var recordList = new List<BaseUserPointRecordAddDto>();
            var gamePointList = new List<GameTeamPointAddDto>();
            foreach (var versusType in versusTypeList)
            {
                var knockoutVersusList = await _gameKnockoutVersusRepository.AsNoTracking().Where(m => m.GameId == game.ID && m.VersusType == versusType).ToListAsync();
                knockoutVersusList = knockoutVersusList.OrderByDescending(m => m.EndRank).ToList();
                foreach (var versus in knockoutVersusList)
                {
                    gamePointList.Clear();
                    //计算比赛积分
                    await CalculatePointAsync(versus, gamePointList);
                    //更新积分
                    if (gamePointList.Any())
                    {
                        foreach (var gamePoint in gamePointList)
                        {
                            var builder = await _gameTeamRepository.UpdatePartialAsync();
                            await builder.Set(m => m.Point, gamePoint.Point)
                                .Where(m => m.GameId == gamePoint.GameId && m.VersusType == gamePoint.VersusType && m.TeamNo == gamePoint.TeamNo)
                                .ExecuteAsync();
                            if (gamePoint.User1Id.HasValue)
                            {
                                recordList.Add(new BaseUserPointRecordAddDto
                                {
                                    BusinessId = versus.ID,
                                    ChangeType = UserPointChangeTypeEnum.GameAdd,
                                    ChangePoint = gamePoint.Point,
                                    UserId = gamePoint.User1Id.Value,
                                    Remark = "比赛获取积分"
                                });
                            }

                            if (gamePoint.User2Id.HasValue)
                            {
                                recordList.Add(new BaseUserPointRecordAddDto
                                {
                                    BusinessId = versus.ID,
                                    ChangeType = UserPointChangeTypeEnum.GameAdd,
                                    ChangePoint = gamePoint.Point,
                                    UserId = gamePoint.User2Id.Value,
                                    Remark = "比赛获取积分"
                                });
                            }
                        }
                    }
                }
            }

            if (recordList.Any())
            {
                //发送用户积分记录消息
                await _capPublisher.PublishAsync(MessageTopic.USER_POINT_RECORD_DETAIL, recordList);
            }
        }

        /// <summary>
        /// 赋值队伍淘汰赛排名
        /// </summary>
        private async Task SetTeamKnockoutRankAsync(GameTeamDto team)
        {
            var knockoutVersus = await _gameKnockoutVersusRepository.AsNoTracking()
                    .Where(m => m.GameId == team.GameId && m.VersusType == team.VersusType && (m.Team1No == team.TeamNo || m.Team2No == team.TeamNo))
                    .OrderBy(m => m.EndRank).ThenByDescending(m => m.StartRank).FirstOrDefaultAsync();
            if (knockoutVersus != null)
            {
#pragma warning disable IDE0045 // 转换为条件表达式
                if (knockoutVersus.EndRank - knockoutVersus.StartRank == 1)
#pragma warning restore IDE0045 // 转换为条件表达式
                {
                    team.KnockoutRank = knockoutVersus.Team1No == team.TeamNo
                        ? knockoutVersus.Team1Score + knockoutVersus.Team1ExtraScore > knockoutVersus.Team2Score + knockoutVersus.Team2ExtraScore ? knockoutVersus.StartRank : knockoutVersus.EndRank
                        : knockoutVersus.Team1Score + knockoutVersus.Team1ExtraScore < knockoutVersus.Team2Score + knockoutVersus.Team2ExtraScore ? knockoutVersus.StartRank : knockoutVersus.EndRank;
                }
                else
                {
                    team.KnockoutRank = knockoutVersus.EndRank;
                }
            }
        }

        /// <summary>
        /// 用户比赛队伍
        /// </summary>
        private async Task<GameTeamDto> GetSelfGameTeamAsync(Guid gameId, Guid userId)
        {
            var quaryable = from team in _gameTeamRepository.AsNoTracking()
                            join user1 in _baseUserRepository.AsNoTracking()
                            on team.User1Id equals user1.ID into user1d
                            from user1 in user1d.DefaultIfEmpty()
                            join user2 in _baseUserRepository.AsNoTracking()
                            on team.User2Id equals user2.ID into user2d
                            from user2 in user2d.DefaultIfEmpty()
                            where team.GameId == gameId && (team.User1Id == userId || team.User2Id == userId)
                            select new GameTeamDto
                            {
                                ID = team.ID,
                                GameId = team.GameId,
                                BusinessId = team.BusinessId,
                                VersusType = team.VersusType,
                                Name = team.Name,
                                HeadUrl = team.HeadUrl,
                                GroupNo = team.GroupNo,
                                TeamNo = team.TeamNo,
                                User1Id = team.User1Id,
                                User1Name = user1.U_RealName ?? user1.U_NickName,
                                User2Id = team.User2Id,
                                User2Name = user2.U_RealName ?? user2.U_NickName,
                                CreateTime = team.CreateTime
                            };
            var result = await quaryable.FirstOrDefaultAsync();
            return result;
        }

        /// <summary>
        /// 自动报名比赛
        /// </summary>
        private async Task AutoJoinGameAsync(Guid gameId, bool isDraw = false)
        {
            var game = await _gameRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == gameId);
            if (game == null)
            {
                return;
            }

            var versusTypeList = JsonSerializer.Deserialize<List<GameVersusEnum>>(game.VersusType);
            var userList = await _baseUserRepository.AsNoTracking().Take(game.LimitCount * 2).ToListAsync();
            var teamList = new List<GameTeam>();
            var teamCount = game.Type != GameTypeEnum.Team && !game.IsTogether ? game.LimitCount * 2 : game.LimitCount;
            for (var i = 0; i < teamCount; i++)
            {
                var businessId = Guid.NewGuid();
                var teamName = $"团队{i + 1}";
                foreach (var versusType in versusTypeList)
                {
                    var userStep = !IsSingle(versusType) && game.IsTogether ? 2 : 1;

                    var team = new GameTeam
                    {
                        GameId = game.ID,
                        VersusType = versusType,
                        GameOrderId = Guid.Empty,
                        BusinessId = businessId,
                        User1Id = userList[i * userStep].ID,
                        User2Id = userStep == 1 ? null : userList[(i * userStep) + 1].ID,
                        JoinState = GameJoinStateEnum.JoinCompleted,
                        PayState = PayOrderStateEnum.Paid,
                        JoinUserId = _currentInfo.UserId,
                        IsTogether = game.IsTogether,
                        Name = game.Type == GameTypeEnum.Team ? teamName : userList[i * userStep].U_RealName ?? userList[i * userStep].U_NickName,
                        HeadUrl = null,
                        TeamNo = ""
                    };

                    teamList.Add(team);
                }
            }

            //保存队伍
            await _gameTeamRepository.BulkAddAsync(teamList);
            if (isDraw)
            {
                //自动抽签保存
                foreach (var versusType in versusTypeList)
                {
                    var drawTeamList = await GroupAutoDrawAsync(new GameRequestDto { GameId = game.ID, VersusType = versusType });
                    if (drawTeamList.Any())
                    {
                        await SaveGroupDrawLotsAsync(new GameGroupDrawLotsRequestDto { GameId = game.ID, VersusType = versusType, TeamList = _mapper.Map<List<GameGroupDrawLotsDetalDto>>(drawTeamList) });
                    }
                }
            }
        }

        /// <summary>
        /// 获取小组成员列表
        /// </summary>
        private async Task<List<GameGroupUserDto>> GetGroupUserListAsync(Guid groupId)
        {
            var quaryable = from groupUser in _gameGroupUserRepository.AsNoTracking()
                            join user1 in _baseUserRepository.AsNoTracking()
                            on groupUser.User1Id equals user1.ID into user1d
                            from user1 in user1d.DefaultIfEmpty()
                            join user2 in _baseUserRepository.AsNoTracking()
                            on groupUser.User2Id equals user2.ID into user2d
                            from user2 in user2d.DefaultIfEmpty()
                            join team in _gameTeamRepository.AsNoTracking()
                            on new { groupUser.GameId, groupUser.VersusType, groupUser.GroupNo, groupUser.TeamNo } equals new { team.GameId, team.VersusType, team.GroupNo, team.TeamNo } into teamd
                            from team in teamd.DefaultIfEmpty()
                            where groupUser.GroupId == groupId
                            select new GameGroupUserDto
                            {
                                ID = groupUser.ID,
                                GameId = groupUser.GameId,
                                VersusType = groupUser.VersusType,
                                GroupNo = groupUser.GroupNo,
                                TeamNo = groupUser.TeamNo,
                                User1Id = groupUser.User1Id,
                                User1Name = user1.U_RealName ?? user1.U_NickName,
                                User1HeadUrl = user1.U_Headportrait,
                                User2Id = groupUser.User2Id,
                                User2Name = user2.U_RealName ?? user2.U_NickName,
                                User2HeadUrl = user2.U_Headportrait,
                                HeadUrl = team.HeadUrl,
                                CreateTime = groupUser.CreateTime,
                                User1TennisLevel = "1.0",
                                User2TennisLevel = "1.0"
                            };
            var list = await quaryable.ToListAsync();
            foreach (var item in list)
            {
                if (item.User1Id.HasValue)
                {
                    item.User1TennisLevel = (await _baseUserService.GetTennisLevelAsync(item.User1Id.Value)).LevelName;
                }

                if (item.User2Id.HasValue)
                {
                    item.User2TennisLevel = (await _baseUserService.GetTennisLevelAsync(item.User2Id.Value)).LevelName;
                }
            }

            return list;
        }
        #endregion
    }
}
